package NG::Gen::Battle::Side;
use strict;
use warnings;

use Data::Dumper;

use NG::Sys::App;
use NG::Sys::Data;
use NG::Gen::Battle::Abilities;


sub new_from_standart {
	my $class = shift;
	my $entry = shift;
	my $proto = app->reference("standart_enemy")->get_by_key($entry);
	my @side;
	my $units = $proto->{troop}{units} || [];
	
	unless(ref $units eq "ARRAY"){
		$units = [ $units ];
	}
	for my $u(@$units){
		if($u->{unit} && $u->{count}){
			push @side,{
				proto_id => $u->{unit},
				count => $u->{count},
			};
		}
	}
	my $stats = array_to_hash($proto->{troop}{stats},stat=>"value");
	my @items;
	my $items = $proto->{troop}{items} || [];
	unless(ref $items eq "ARRAY"){
		$items = [ $items ];
	}
	for my $i(@$items){
		if($i->{item} && $i->{count}){
			for(1 .. $i->{count}){
				push @items,$i->{item};
			}
		}
	}
	return bless {
		title => $proto->{title},
		units => \@side,
		items => \@items,
		stats => $stats,
		},$class;
}
sub new_from_user {
	my $class = shift;
	my $user = shift;
	my $leader = shift;
	my @side;
	for my $u(@{$leader->units->list}){
		if($u->{count}){
			push @side,{
				proto_id => $u->{proto_id},
				count => $u->{count},
			};
		}
	}
	my $stats = $user->stat->read_data;
	my @items;
	for my $i(@{$leader->items->list}){
		push @items,$i->{proto_id};
	}
	return bless {
		title => $user->chat_login,
		units => \@side,
		items => \@items,
		stats => $stats,
		},$class;
}


sub prepare {
	my $side = shift;
	my $diff = shift;
	my $ary = $side->{units};

	my $mf = app->reference("unit_modif");
	my $abils = app->reference("unit_abilities");
	my $ref = app->reference("units");
	my $iref = app->reference("items");

	my @mf = map {$_->{name}} @{$mf->get_list};
	my @i = (0) x @mf;
	
	my %item_bonus;
	@item_bonus{@mf} = @i;
	for my $i(@{$side->{items}}){
		my $ri = $iref->get_by_key($i);
		my $mf;
		if(exists $ri->{modif} and $mf = $ri->{modif}){
			for my $m(@$mf){
				$item_bonus{$m->{modif}} += $m->{value};
			}
		}
	}

	my @war;
	my @all;
	my $total = 0;
	my $war = 0;
	my %ua;
	for my $u(@$ary){
		next unless $u->{count};
		my %unit;
		@unit{@mf} = @i;
		my $p = $ref->get_by_key($u->{proto_id});
		unless($p){
			die "bad proto $u->{proto_id}";
		}
		array_to_hash(\%unit,$p->{modif}, modif => "value");
		while(my($m,$v) = each %$diff){
			$unit{$m} = int(($unit{$m} + ($unit{$m} && $item_bonus{$m})) * $v);
		}
		$unit{count} = $u->{count};
		$unit{title} = $p->{title};
		$unit{type} = $p->{type};
		
		if($unit{type} == 1){
			push @war,\%unit;
			$war += $unit{count};
		}elsif($unit{type} == 2 && $p->{abilities} && (my $at = $p->{abilities}{abilities})){
			my $ap = $abils->get_list({name=>$at})->[0];
			my $ref;
			if($ap and $ref = NG::Gen::Battle::Abilities->can($at)){
				$unit{ability} = {
					an => $at,
					sub => $ref,
					chance => $p->{abilities}{chance},
					value => $p->{abilities}{value},
				};
				push @{$ua{$ap->{stage}}{$ap->{target}}}, \%unit;
			}else{
				die "bad ability type '$at'";
			}
		}
		push @all,\%unit;
		
		$total += $unit{count};
		$unit{rest} = $unit{health};
		$unit{count}--;
	}
	$side->{ua} = \%ua;
	$side->{war} = \ @war;
	$side->{all} = \@all;
	$side->{tc} = $total;
	$side->{wc} = $war;
}


sub choose_target {
	my $side = shift;
	my $p = rand($side->{tc});
	my $l = @{$side->{all}};
	for(my $i = 0; $i < $l; $i++){
		my $u = $side->{all}[$i];
		my $c = $u->{count} + ($u->{rest} ? 1 : 0);
		if($p > $c){
			$p -= $c;
		}else{
			return $i;
		}
	}
	app->logger->info("not choose($p,$l): ".Dumper($side));
	exit;
}
sub _get_next {
	my $side = shift;
	my $c;
	unless($c = @{$side->{order}}){
		return 0;
	}
	my $pos = rand($c);
	my $u = $side->{order}[$pos];
	unless($u->{current}++ < $u->{count}){
		splice @{$side->{order}},$pos,1;
	}
	return $u;
}
sub get_next {
	my $side = shift;
	for(;;){
		my $u = _get_next($side);
		unless($u){
			return 0;
		}
		if($u->{rest}){
			return $u;
		}
	}
}
sub check_before_4a {
	my ($side,$dir,$unit,$log) = @_;
	apply_ability($dir,$side->{ua}{1}{1},$unit,$log);
}
sub check_before_4t {
	my ($side,$dir,$unit,$log) = @_;
	apply_ability($dir,$side->{ua}{1}{2},$unit,$log);
}
sub check_after_4a {
	my ($side,$dir,$unit,$log) = @_;
	apply_ability($dir,$side->{ua}{2}{1},$unit,$log);
}
sub check_after_4t {
	my ($side,$dir,$unit,$log) = @_;
	apply_ability($dir,$side->{ua}{2}{2},$unit,$log);
}

sub reset_side {
	my $side = shift;

	my @order = @{$side->{war}};
	for(@order){
		$_->{current} = 0;
		$_->{again} = 0;
	}
	$side->{order} = \@order;

	for my $s(values  %{$side->{ua}||{}}){
		for my $t(values  %{$s||{}}){
			$_->{ability}{count} = 0 for @{$t||[]};
		}
	}
	$side->{damage} = 0;

}
1;
